package org.kgduyjj.toolbox.algorithms;

import java.util.Date;

import org.apache.commons.lang.StringUtils;
import org.kgduyjj.toolbox.DateUtil;
import org.kgduyjj.toolbox.MD5Util;
import org.kgduyjj.toolbox.exception.AlgorithmsException;

/**
 * 唯一码生成器
 * 
 * @author Kgduyjj
 * @since 2020-07-26
 * @version Alpha-1.42
 *
 */
public final class SerialCodeGenerator {
	/** wquncopyrightable 不可赋予版权 (17位) */
	private static final char[] REMIX = { 'W', 'Q', 'U', 'N', 'C', 'O', 'P', 'Y', 'R', 'I', 'G', 'H', 'T', 'A', 'B',
			'L', 'E' };
	/** 相乘因子17位 */
	private static final int[] POWER = { 5, 6, 3, 13, 3, 16, 5, 16, 11, 16, 3, 4, 6, 10, 16, 6, 2 };
	/** 锁对象，可以为任意对象 */
	private static Object lockObj = "lockerOrder";
	private static final long DEFAULT_START_SORT = 0L;
	/** 订单号生成计数器 */
	private static long currentSortNo = DEFAULT_START_SORT;
	/** 每毫秒生成订单号数量最大值 */
	private static long maxSortSize = 1000;
	/** SerialNo 格式化字符串 */
	private static final String SN_FMT = "yyyyMMddHHmmssms";

	private static final String DEFAULT_PERFIX = "SCG";

	/**
	 * 生成头部标识
	 * 
	 * @param gsn
	 * @return
	 */
	public static String genPerfix(String seed) {
		if (seed == null || seed.length() == 0) {
			throw new AlgorithmsException("不可用的种子[内容为空]");
		}
		int index = _simpleDigit(seed);
		char simpleWord = REMIX[index];
		int pindex = _powerDigit(seed);
		char powerWord = REMIX[pindex];
		int cindex = (_simpleDigit(seed) - 1);
		// 若枚举CODE超过17，则做计算规则以保证REMIX不会越位。
		if (cindex > 17) {
			cindex = cindex * 11 % 17;
		}
		char cWord = REMIX[cindex];
		return convertToString(powerWord, simpleWord, cWord);
	}

	/**
	 * 生成唯一标识码
	 * 
	 * @param gsn
	 * @return
	 */
	public static String genSerialNo(String seed) {
		StringBuffer buffer = new StringBuffer(genPerfix(seed));
		buffer.append("-");
		buffer.append(MD5Util.MD5X16(genOrginalSerialNo(genPerfix(seed))));
		return buffer.toString();
	}

	/**
	 * 将char数组转换为字符串
	 * 
	 * @param remix
	 * @return
	 */
	private static String convertToString(char... charArr) {
		if (charArr == null)
			return DEFAULT_PERFIX;
		return String.valueOf(charArr);
	}

	/**
	 * 简单求和
	 * 
	 * @param seed
	 * @return
	 */
	private static int _simpleDigit(String seed) {
		if (StringUtils.isBlank(seed)) {
			return -5;
		}
		byte[] byteText = seed.getBytes();
		int sum = 0;
		for (int i = 0; i < byteText.length; i++) {
			sum += Math.abs(byteText[i]);
		}
		return (sum * 31 % 17);
	}

	/**
	 * Power 乘积
	 * 
	 * @param seed
	 * @return
	 */
	private static int _powerDigit(String seed) {
		if (StringUtils.isBlank(seed)) {
			return -7;
		}
		char[] charArr = seed.toCharArray();
		int iSum = 0;
		for (char c : charArr) {
			for (int j = 0; j < POWER.length; j++) {
				int n = Character.getNumericValue(c);
				iSum += (Math.abs(n) * POWER[j]);
				continue;
			}
		}
		return (iSum % 17);
	}

	/**
	 * 生成原始唯一识别码
	 * 
	 * @param orginalText
	 * @return
	 */
	private static String genOrginalSerialNo(String perfix) {
		// 前缀
		StringBuffer buffer = new StringBuffer(perfix);
		// 串行号分隔符
		buffer.append("#");
		// 当前时间，毫秒级
		buffer.append(DateUtil.format(new Date(), SN_FMT));
		// 顺序号
		buffer.append(genSortNumber());
		return buffer.toString();
	}

	/**
	 * 生成顺序号码，从0开始，根据位数获取x个0到x个9的顺序号码
	 * 
	 */
	private static String genSortNumber() {
		String finOrderNum = "";
		try {
			synchronized (lockObj) {
				// 计数器到最大值归零，可扩展更大，目前1毫秒处理峰值1000个，1秒100万
				if (currentSortNo > maxSortSize) {
					currentSortNo = DEFAULT_START_SORT;
				}
				// 组装订单号
				String countStr = maxSortSize + currentSortNo + "";
				finOrderNum = countStr.substring(1);
				currentSortNo++;
				// Thread.sleep(1000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return finOrderNum;
	}
}
